using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using EnvDTE;
using SmartStringResources.CodeDom;
using SmartStringResources.Dte;

namespace SmartStringResources
{
    public class CodeGenerator
	{
		private readonly CodeDomProvider _codeDomProvider;
		private readonly IFileSystemService _fileSystemService;

		public CodeGenerator(CodeDomProvider codeDomProvider, IFileSystemService fileSystemService)
		{
			_codeDomProvider = codeDomProvider;
			_fileSystemService = fileSystemService;
		}

	    private string GetNamespace(Project project, string resourceFile)
		{
			var defaultNamespace = GetDefaultNamespace();
			var resourceProjectItem = project.GetProjectItemByFullPath(resourceFile);
			if (resourceProjectItem == null)
				return defaultNamespace;

	        if (resourceProjectItem.GetCustomTool() == "GlobalResourceProxyGenerator")
	            return "Resources";

			var customNamespace = resourceProjectItem.GetCustomToolNamespace();
			return !string.IsNullOrEmpty(customNamespace) ? GetValidNamespaceName(customNamespace) : defaultNamespace;
		}

	    private string GetDefaultNamespace()
		{
			return CallContext.LogicalGetData("NamespaceHint") as string;
		}

	    private string GetValidNamespaceName(string @namespace)
		{
			var parts = @namespace.Split('.').AsEnumerable();

			if (parts.Count() == 1)
				return _codeDomProvider.GetValidIdentifier(@namespace, true);

			return string.Join(".", parts.Select(p => _codeDomProvider.GetValidIdentifier(p)));
		}

		public string GenerateContents(Project project, string resourceFile, GeneratorOptions options = null)
		{
			var stringWriter = new StringWriter();
			var resourcesNamespace = GetNamespace(project, resourceFile);
			var rootNamespace = project.GetRootNamespace();
			var resourceInfo = new ResourceFileInfo(rootNamespace, resourcesNamespace, resourceFile);

			using (var stream = _fileSystemService.OpenFileStream(resourceFile))
			{
				var compileUnit = GenerateCompileUnit(stream, resourceInfo, options);
				_codeDomProvider.GenerateCodeFromCompileUnit(compileUnit, stringWriter, new CodeGeneratorOptions
				{
					BlankLinesBetweenMembers = true,
					BracingStyle = "Block",
					ElseOnClosing = false,
					IndentString = "    "
				});
				return stringWriter.GetStringBuilder().ToString();
			}
		}

		public CodeCompileUnit GenerateCompileUnit(Stream resource, string resourceFileName, string rootNamespace, string resourcesNamespace, GeneratorOptions options = null)
		{
			var resourceFileInfo = new ResourceFileInfo(rootNamespace, resourcesNamespace, resourceFileName);
			return GenerateCompileUnit(resource, resourceFileInfo, options);
		}

		private CodeCompileUnit GenerateCompileUnit(Stream resource, ResourceFileInfo resourceInfo, GeneratorOptions options = null)
		{
			using (var reader = new StreamReader(resource))
			{
			    var generator = new CompileUnitGenerator(_codeDomProvider);
				return generator.GenerateCompileUnit(reader, resourceInfo, options);
			}
		}
	}
}